import React, { useRef, useEffect, useState, useMemo } from 'react'
import G6, { Graph, TreeGraph } from '@antv/g6'
import { IG6GraphEvent, TreeGraphData } from '@antv/g6/lib/types'
import { IEdge, INode } from '@antv/g6/lib/interface/item'

let addedCount = 0
// Register a custom behavior: add a node when user click the blank part of canvas
G6.registerBehavior('click-add-node', {
	// Set the events and the corresponding responsing function for this behavior
	getEvents() {
		// The event is canvas:click, the responsing function is onClick
		return {
			'canvas:click': 'onClick',
		}
	},
	// Click event
	onClick(ev) {
		const self = this
		const graph = self.graph
		// Add a new node
		const { x, y } = graph.getPointByClient(ev.clientX, ev.clientY)
		graph.addItem('node', {
			x: x,
			y: y,
			id: `node-${addedCount}`, // Generate the unique id
		})

		addedCount++
	},
})

G6.registerBehavior('click-add-child', {
	// Set the events and the corresponding responsing function for this behavior
	getEvents() {
		// The event is canvas:click, the responsing function is onClick
		return {
			'node:click': 'onClick',
		}
	},
	// Click event
	onClick(ev) {
		const self = this
		const graph = self.graph
		const item = ev.item
		if (item) {
			const model = item.getModel()
			if (!model.children) {
				model.children = []
			}
			// Add a new node
			const { x, y } = graph.getPointByClient(ev.clientX, ev.clientY)
			model.children.push({
				x: x,
				y: y,
				id: `node-${addedCount}`, // Generate the unique id
			})
			graph.updateChild(model, model.id)
			addedCount++
		}
	},
})

G6.registerBehavior('del-node-and-edge', {
	// Set the events and the corresponding responsing function for this behavior
	getEvents() {
		return {
			'node:click': 'onClick', // The event is canvas:click, the responsing function is onClick
			'edge:click': 'onEdgeClick', // The event is edge:click, the responsing function is onEdgeClick
		}
	},
	// The responsing function for node:click defined in getEvents
	onClick(ev) {
		const self = this
		const node = ev.item
		const graph = self.graph
		// const itemController = graph.get("itemController");
		// itemController.removeItem(node);
		graph.removeItem(node)
	},
	onEdgeClick(ev) {
		const self = this
		const currentEdge = ev.item
		const graph = self.graph
		graph.removeItem(currentEdge)
	},
})

// Initial data
const data = {
	id: 'Modeling Methods',
	children: [
		{
			id: 'Classification',
			children: [
				{ id: 'Logistic regression' },
				{ id: 'Linear discriminant analysis' },
				{ id: 'Rules' },
				{ id: 'Decision trees' },
				{ id: 'Naive Bayes' },
				{ id: 'K nearest neighbor' },
				{ id: 'Probabilistic neural network' },
				{ id: 'Support vector machine' },
			],
		},
		{
			id: 'Consensus',
			children: [
				{
					id: 'Models diversity',
					children: [
						{ id: 'Different initializations' },
						{ id: 'Different parameter choices' },
						{ id: 'Different architectures' },
						{ id: 'Different modeling methods' },
						{ id: 'Different training sets' },
						{ id: 'Different feature sets' },
					],
				},
				{
					id: 'Methods',
					children: [{ id: 'Classifier selection' }, { id: 'Classifier fusion' }],
				},
				{
					id: 'Common',
					children: [{ id: 'Bagging' }, { id: 'Boosting' }, { id: 'AdaBoost' }],
				},
			],
		},
		{
			id: 'Regression',
			children: [
				{ id: 'Multiple linear regression' },
				{ id: 'Partial least squares' },
				{ id: 'Multi-layer feedforward neural network' },
				{ id: 'General regression neural network' },
				{ id: 'Support vector regression' },
			],
		},
	],
}

let graph

function App() {
	const ref = useRef(null)
	const [state, setState] = useState('H')
	const [show, setShow] = useState(false)
	const [changeItem, setChangeItem] = useState()
	const [label, setLabel] = useState('')
	const [fill, setfill] = useState('')
	const [fontSize, setFontSize] = useState(0)
	useMemo(() => {
		G6.registerBehavior('click-change-style', {
			// Set the events and the corresponding responsing function for this behavior
			getEvents() {
				return {
					'node:click': 'onClick', // The event is canvas:click, the responsing function is onClick
				}
			},
			// The responsing function for node:click defined in getEvents
			onClick(ev) {
				const item = ev.item
				const model = item.getModel()
				const value = model.label
				const f = model.style?.fill
				const labelcfg = model.labelCfg
				if (typeof value === 'string') {
					//将节点的值赋给input并绑上onchange给它
					setLabel(value)
					if (f) {
						setfill(f)
					} else {
						setfill('')
					}
					if (labelcfg && labelcfg.style && labelcfg.style.fontSize) {
						setFontSize(labelcfg.style.fontSize)
					} else {
						const nlabelcfg = {
							style: {
								fontSize: 14,
							},
						}
						model.labelCfg = nlabelcfg
						setFontSize(14)
					}
					setChangeItem(item) //要调用更新，最小是item item才有update
				}
			},
		})
	}, [])

	useEffect(() => {
		graph = new G6.TreeGraph({
			container: ref.current,
			width: 800,
			height: 800,
			// The sets of behavior modes
			modes: {
				// Defualt mode
				default: ['drag-node', 'drag-canvas', 'zoom-canvas', 'collapse-expand'],
				// Adding node mode
				addNode: ['click-add-node', 'click-select'],
				// Adding edge mode
				del: ['del-node-and-edge'],
				addChild: ['click-add-child', 'click-select'],
				changeStyle: ['click-change-style'],
			},
			// The node styles in different states
			nodeStateStyles: {
				// The node styles in selected state
				selected: {
					stroke: '#666',
					lineWidth: 2,
					fill: 'steelblue',
				},
			},
			layout: {
				type: 'mindmap',
				direction: state, // H / V / LR / RL / TB / BT
				getHeight: () => {
					return 16
				},
				getWidth: () => {
					return 16
				},
				getVGap: () => {
					return 10
				},
				getHGap: () => {
					return 50
				},
			},
			defaultEdge: {
				type: 'cubic-horizontal',
				style: {
					stroke: '#A3B1BF',
				},
			},
		})
		graph.node(function (node) {
			return {
				label: node.id,
			}
		})
		graph.data(data)
		graph.render()
		graph.fitView()
		return () => graph.destroy()
	}, [state])

	const handleChange = (e) => {
		setLabel(e.target.value)
		//修改state后改变节点Label
		if (changeItem) {
			//其他样式控制同理这么操作
			const model = changeItem.getModel()
			model.label = e.target.value
			changeItem.update(model)
		}
	}
	const handleColor = (e) => {
		setfill(e.target.value)
		//修改state后改变节点Label
		if (changeItem) {
			//其他样式控制同理这么操作
			const model = changeItem.getModel()
			if (model.style) {
				model.style.fill = e.target.value
				changeItem.update(model)
			}
		}
	}
	const handleFontSize = (e) => {
		const num = parseFloat(e.target.value)
		setFontSize(num)
		//修改state后改变节点Label
		if (changeItem) {
			//其他样式控制同理这么操作
			const model = changeItem.getModel()
			if (model.labelCfg) {
				if (model.labelCfg.style) {
					model.labelCfg.style.fontSize = num
				} else {
					model.labelCfg.style = {
						fontSize: num,
					}
				}

				changeItem.update(model)
			}
		}
	}

	return (
		<div>
			<button
				onClick={() => {
					graph.setMode('addNode')
					setShow(false)
				}}
			>
				添加节点
			</button>
			<button
				onClick={() => {
					graph.setMode('addChild')
					setShow(false)
				}}
			>
				添加孩子
			</button>
			<button
				onClick={() => {
					graph.setMode('default')
					setShow(false)
				}}
			>
				默认模式
			</button>
			<button
				onClick={() => {
					graph.setMode('del')
					setShow(false)
				}}
			>
				删除模式
			</button>
			<span>请选择布局模式：</span>
			<select
				value={state}
				onChange={(e) => {
					setState(e.target.value)
					setShow(false)
				}}
			>
				<option value="H">H</option>
				<option value="V">V</option>
				<option value="LR">LR</option>
				<option value="RL">RL</option>
				<option value="TB">TB</option>
				<option value="BT">BT</option>
			</select>
			<button
				onClick={() => {
					setShow(true)
					graph.setMode('changeStyle')
				}}
			>
				修改样式
			</button>
			<div style={{ display: show ? 'block' : 'none' }}>
				<div>
					修改label
					<input value={label} onChange={handleChange}></input>
				</div>
				<div>
					修改颜色
					<input value={fill} onChange={handleColor}></input>
				</div>
				<div>
					修改字体
					<input value={fontSize} onChange={handleFontSize}></input>
				</div>
			</div>
			<div ref={ref}></div>
		</div>
	)
}
export default App
